package bl;

import java.util.ArrayList;
import java.util.List;

import objects.Board;
import objects.Card;
import objects.CardType;
import objects.Character;
import objects.Containable;
import objects.Envelope;
import objects.HypoResult;
import objects.MurderableRoom;
import objects.Player;
import objects.Room;
import objects.Weapon;

public class GameManager {

    /**
     * The method moves character and weapon to a room
     */
    private static void moveCharacterAndWeaponToRoom(int roomNumber, int characterId, int weaponId)
    {
    	for (int i = 0; i < Board.getInstance().getRooms().length; i++)
    	{
			if (Board.getInstance().getRooms()[i] instanceof MurderableRoom)
			{
				if (((MurderableRoom)Board.getInstance().getRooms()[i]).getRoom().ordinal() == roomNumber)
				{
					roomNumber = i;
					break;
				}
			}
		}
	
		Character character = Character.values()[characterId];
		
		for (Containable containable : Board.getInstance().getRooms()) {
			
			// Check if the character is in this room
			if (containable.isCharacterIn(character))
			{
				containable.participantExit(character);
				
				// Enter the character to the room number roomNumber
				
				Board.getInstance().getRooms()[roomNumber].participantEnter(character);
				
				break;
			}
		}
    	
    	//Find the weapon and move it to the room number roomNumber
    	for (Containable containable : Board.getInstance().getRooms()) {
			
    		if (containable instanceof MurderableRoom)
    		{
    			Weapon weapon = Weapon.values()[weaponId];
    			
    			// Check if the weapon is in this room
				if (((MurderableRoom)containable).isWeaponIn(weapon))
				{
					((MurderableRoom)containable).removeWeapon(weapon);
				
					// Enter the character to the room number roomNumber
					((MurderableRoom)Board.getInstance().getRooms()[roomNumber]).addWeapon(weapon);
					
					break;
				}
    		}
		}
    	
    	for (Player player : Board.getInstance().getBdGameData().getPlayers())
    	{
			if (player.getCharacter().ordinal() == characterId)
			{
				Board.getInstance().getRooms()[player.getRoomNumber()].participantExit(player);
				// Enter the player to the room number roomNumber
				Board.getInstance().getRooms()[roomNumber].participantEnter(player);
				player.setRoomNumber(roomNumber);
				break;
			}
		}
    	
    }
    

    /**
     *  Returns True if the parameters sent are the cards that the envelope contains.
     */
    public static boolean winOrLose(Room rmAccusedRoom, Character chAccusedChar, Weapon wpAccusedWeapon)
    {
    	boolean bDidWin = false;
    	Envelope envelope = Board.getInstance().getBdGameData().getEnvelope();
    	Card crdRoom = new Card();
    	crdRoom.setType(CardType.ROOM);
    	crdRoom.setName(rmAccusedRoom.name());
    	
    	Card crdChar = new Card();
    	crdChar.setType(CardType.CHARACTER);
    	crdChar.setName(chAccusedChar.name());
    	
    	Card crdWeap = new Card();
    	crdWeap.setType(CardType.WEAPON);
    	crdWeap.setName(wpAccusedWeapon.name());
    	
    	if (envelope.getRoomCard().equals(crdRoom) &&
        		envelope.getCharacterCard().equals(crdChar) &&
        		envelope.getWeaponCard().equals(crdWeap))
        	{
    			bDidWin = true;
        	}
    	
    	return bDidWin;
    	
    }
    
    /**
     * Make an assumption. if true, return empty array of contradition cards.
     * if false, return the player who contradicted and a cards that can be used as contradiction cards. 
     */
    public static HypoResult makehypothesis(Room rmAccusedRoom, Character chAccusedChar, Weapon wpAccusedWeapon)
    {
    	List<Card> contradictCards = new ArrayList<Card>();
    	Player contPlayer = null;
    	moveCharacterAndWeaponToRoom(rmAccusedRoom.ordinal(), chAccusedChar.ordinal(), wpAccusedWeapon.ordinal());
    	Card crdRoom = new Card();
    	crdRoom.setType(CardType.ROOM);
    	crdRoom.setName(rmAccusedRoom.name());
    	
    	Card crdChar = new Card();
    	crdChar.setType(CardType.CHARACTER);
    	crdChar.setName(chAccusedChar.name());
    	
    	Card crdWeap = new Card();
    	crdWeap.setType(CardType.WEAPON);
    	crdWeap.setName(wpAccusedWeapon.name());
    	Envelope envelope = Board.getInstance().getBdGameData().getEnvelope();
    	
    	if (!(envelope.getRoomCard().equals(crdRoom) &&
    		envelope.getCharacterCard().equals(crdChar) &&
    		envelope.getWeaponCard().equals(crdWeap)))
    	{
    		// A list that holds all the cards that the player holds that contradicts the guess of the current player
        	
        	// Make a list of other players to contradict the hypothesis
        	List<Player> contradictPlayers = new ArrayList<Player>();
        	
        	List<Player> players = Board.getInstance().getBdGameData().getPlayers();
        	int nCurrPlayer = Board.getInstance().getCurrPlayer();
        	
        	for (int i = 0; i < players.size() - 1; i++) 
        	{
        		contradictPlayers.add(players.get((nCurrPlayer + (i + 1)) % players.size()));
			}

        	boolean bFoundContPlayer = false;
    		// Run over the other players and find out if there is a player with contradicting card
    		for (Player player : contradictPlayers)
        	{
    			if (bFoundContPlayer)
    			{
    				break;
    			}
    			
    			//contradictPlayer = player;
    			
    			// Run over the cards list of the player
        		for (Card card : player.getCardsList()) {
        			
        			// If the card of the player is a weapon card
        			if (card.getType() == CardType.WEAPON)
        			{
        				// If the player holds a card that contradicts the hypothesis
        				if (card.getName().equals(crdWeap.getName()))
        				{
        					// Add a card to the list of contradicting cards
        					contradictCards.add(card);
        					bFoundContPlayer = true;
        					contPlayer = player;
        				}
        			}
        			
        			// If the card of the player is a weapon card
        			if (card.getType() == CardType.CHARACTER)
        			{
        				// If the player holds a card that contradicts the hypothesis
        				if (card.getName().equals(crdChar.getName()))
        				{
        					contradictCards.add(card);
        					bFoundContPlayer = true;
        					contPlayer = player;
        				}
        			}
        			
        			// If the card of the player is a weapon card
        			if (card.getType() == CardType.ROOM)
        			{
        				if (card.getName().equals(crdRoom.getName()))
        				{
        					contradictCards.add(card);
        					bFoundContPlayer = true;
        					contPlayer = player;
        				}
        			}
    			}
        	}    		
    	}

    	// Build the result.
    	HypoResult hr = new HypoResult();
    	
    	if (contPlayer != null && (contPlayer.getType().equals("COMPUTER") || !contPlayer.isInTheGame()))
    	{
    		hr.setCards(contradictCards.subList(0, 1));
    	}
    	else
    	{
    		hr.setCards(contradictCards);
    	}
    	
    	hr.setContPlayer(contPlayer);
    	return hr;
		
	}
}
